# 示例：create_react_agent-hitl.py
# 人机交互（Human-in-the-loop）的 REACT 代理实现
# 本示例展示了如何创建一个可以在工具执行前暂停等待人工输入的智能代理

import os
from typing import Literal

from dotenv import load_dotenv
# 从 langchain_core.tools 导入 tool 装饰器，用于创建工具函数
from langchain_core.tools import tool
from langchain_openai import ChatOpenAI

# 加载环境变量（从 .env 文件）
load_dotenv()

# 初始化大语言模型（LLM）
# 使用 Qwen3-32B 模型，配置流式输出和温度参数
llm = ChatOpenAI(
    api_key=os.getenv("MODELSCOPE_API_KEY"),  # 从环境变量获取 API 密钥
    openai_api_base=os.getenv("MODELSCOPE_API_BASE"),  # 从环境变量获取 API 基础地址
    model="Qwen/Qwen3-32B",  # 指定使用的模型
    streaming=True,  # 启用流式输出
    temperature=0.7  # 设置创造性程度，0.7 表示中等创造性
)


# 定义一个工具函数 get_weather，用于获取天气信息
@tool
def get_weather(city: Literal["nyc", "sf"]):
    """使用此工具获取天气信息。"""
    if city == "nyc":
        return "纽约可能是多云天气"
    elif city == "sf":
        return "旧金山总是阳光明媚"
    else:
        raise AssertionError("未知城市")


# 将工具放入一个列表中，供代理使用
tools = [get_weather]

# 导入检查点器，用于启用人机交互模式
from langgraph.checkpoint.memory import MemorySaver

# 初始化 MemorySaver 实例，用于保存对话状态
memory = MemorySaver()

# 导入预构建的 REACT 代理创建函数
from langgraph.prebuilt import create_react_agent

# 使用指定的模型、工具和检查点器创建 REACT 代理
# interrupt_before=["tools"] 表示在执行工具前暂停，等待人工输入
graph = create_react_agent(
    llm,
    tools=tools,
    interrupt_before=["tools"],  # 在工具执行前中断，等待人工确认
    checkpointer=memory  # 使用内存检查点器保存状态
)


# 定义一个函数用于打印流数据
def print_stream(stream):
    """
    打印流式输出的消息内容

    Args:
        stream: 图生成的流式输出
    """
    for s in stream:
        message = s["messages"][-1]  # 获取最新的消息
        if isinstance(message, tuple):
            print(message)
        else:
            message.pretty_print()  # 格式化打印消息


# 配置图运行参数
config = {"configurable": {"thread_id": "42"}}  # 线程ID，用于区分不同的对话会话

# 输入参数，包含用户的初始消息
inputs = {"messages": [("user", "旧金山的天气怎么样？")]}

print("=== 第一次执行 ===")
# 执行图并打印流输出
print_stream(graph.stream(inputs, config, stream_mode="values"))

# 获取图的当前状态快照
snapshot = graph.get_state(config)
print("下一步操作: ", snapshot.next)  # 打印下一步将要执行的操作

print("\n=== 继续执行 ===")
# 继续执行图（传入 None 表示继续之前的执行）
print_stream(graph.stream(None, config, stream_mode="values"))